package com.heatingcharge.service.sys.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.heatingcharge.common.exception.BaseException;
import com.heatingcharge.common.util.ResponseCodeEnum;
import com.heatingcharge.dto.SysUserDTO;
import com.heatingcharge.entity.sys.SysUser;
import com.heatingcharge.entity.unit.ResZone;
import com.heatingcharge.mapper.sys.SysUserMapper;
import com.heatingcharge.param.SysUserParam;
import com.heatingcharge.security.JwtUser;
import com.heatingcharge.security.util.JwtUtil;
import com.heatingcharge.security.util.SecurityUtil;
import com.heatingcharge.service.sys.ISysMenuService;
import com.heatingcharge.service.sys.ISysUserRoleService;
import com.heatingcharge.service.sys.ISysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 后台管理用户  服务实现类
 * </p>
 *
 * @author devin.jiang
 * @since 2019-06-27
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    ISysMenuService menuService;
    @Autowired
    ISysUserRoleService userRoleService;

    @Override
    public String login(JwtUser jwtUser) {
        Authentication authentication=null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername()去验证用户名和密码，
            // 如果正确，则存储该用户名密码到security 的 context中
            authentication=authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(jwtUser.getUsername(),jwtUser.getPassword()));
        } catch (Exception e) {
            if (e instanceof UsernameNotFoundException){
                throw new BaseException("登录用户:" + jwtUser.getUsername() + " 不存在", 402);
            }
            if (e instanceof BadCredentialsException) {
                throw new BaseException("用户名或密码错误", 402);
            } else if (e instanceof LockedException) {
                throw new BaseException("账户被锁定,请联系管理员", 402);
            }
            else if (e instanceof DisabledException) {
                throw new BaseException("账户被禁用", 402);
            } else if (e instanceof AccountExpiredException) {
                throw new BaseException("账户过期无法验证", 402);
            } else {
                throw new BaseException(e.getMessage(), 402);
            }
        }
        //存储认证信息
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //生成token
        JwtUser userDetail = (JwtUser) authentication.getPrincipal();
        return JwtUtil.generateToken(userDetail);
    }

    @Override
    public SysUser findByName(String username) {
        return baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .select(SysUser::getId,SysUser::getUsername,SysUser::getPassword,SysUser::getRealName,SysUser::getStatus)
                .ne(SysUser::getStatus,2)
                .eq(SysUser::getUsername,username));

    }

    @Override
    public Set<String> findPermsByUserId(Integer userId) {
        return menuService.findPermsByUserId(userId).stream().filter(StringUtils::isNotEmpty).collect(Collectors.toSet());
    }

    @Override
    public Set<String> findRoleIdByUserId(Integer userId) {
        return userRoleService.selectUserRoleByUserId(userId)
                .stream()
                .map(sysUserRole -> "ROLE_"+sysUserRole.getRoleId())
                .collect(Collectors.toSet());
//        return null;
    }

    @Override
    public IPage<SysUserDTO> getSysUsers(Page page, SysUserDTO sysUserDTO) {
        return baseMapper.selectSysUsers(page,sysUserDTO);
    }

    @Override
    public boolean save(SysUserParam sysUserParam) {
        if (checkExist(sysUserParam.getUsername(),null)){
            throw new BaseException(ResponseCodeEnum.USER_EXIST.getMessage(),ResponseCodeEnum.USER_EXIST.getCode());
        }
        JwtUser user = SecurityUtil.getUser();
        SysUser sysUser=new SysUser();
        BeanUtils.copyProperties(sysUserParam,sysUser);
        sysUser.setCreatedTime(new Date());
        sysUser.setCreatedBy(user.getRealName());
        sysUser.setPassword(new BCryptPasswordEncoder().encode(sysUserParam.getPassword()));
        return baseMapper.insert(sysUser)>0;
    }

    @Override
    public boolean update(SysUserParam sysUserParam) {
        if (checkExist(sysUserParam.getUsername(),sysUserParam.getId())){
            throw new BaseException(ResponseCodeEnum.USER_EXIST.getMessage(),ResponseCodeEnum.USER_EXIST.getCode());
        }
        JwtUser user = SecurityUtil.getUser();
        SysUser sysUser=new SysUser();
        BeanUtils.copyProperties(sysUserParam,sysUser);
        sysUser.setUpdatedTime(new Date());
        sysUser.setUpdatedBy(user.getRealName());
        sysUser.setPassword(new BCryptPasswordEncoder().encode(sysUserParam.getPassword()));
        return baseMapper.updateById(sysUser)>0;
    }

    private boolean checkExist(String name,Integer id){
        QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("username",name);
        if (id!=null){
            queryWrapper.ne("id",id);
        }
        return this.list(queryWrapper).size()>0;
    }
}
